﻿using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using Foundation.MarkupExtensions;
using ICSharpCode.AvalonEdit.Document;

namespace Poet.Modules
{
    /// <summary>
    /// 
    /// </summary>
    public class SpellCheckModule
    { 
        private readonly TextDocument _document;
        private readonly SpellColorizer _spellColorizer;

        /// <summary>
        /// Initializes a new instance of the <see cref="SpellCheckModule"/> class.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <param name="spellColorizer">The spell colorizer.</param>
        public SpellCheckModule(TextDocument document, SpellColorizer spellColorizer)
        {
            _document = document;
            _spellColorizer = spellColorizer;
        }

        /// <summary>
        /// Generates the spell menu.
        /// </summary>
        /// <param name="word">The word.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="length">The length.</param>
        /// <returns></returns>
        public IEnumerable<Control> GenerateSpellMenu(string word, int offset, int length)
        {
            word = word ?? string.Empty;
            var spellMenuItems = new List<Control>();
            var wordMenuItem = new MenuItem
                {
                    Header = string.IsNullOrWhiteSpace(word) ? Localizing.ProvideValue("None", "[{0}]") : word
                };

            spellMenuItems.Add(wordMenuItem);
            spellMenuItems.Add(new Separator());

            var suggestions = new List<string>();
            foreach (var spellChecker in SpellColorizer.SpellCheckers)
            {
                var item = new MenuItem
                {
                    Header = spellChecker.WebService.Name,
                    IsChecked = _spellColorizer.UsedSpellCheckers.Contains(spellChecker),
                };

                var checker = spellChecker;
                item.PreviewMouseLeftButtonDown += (sender, args) =>
                {
                    if (!Equals(item, args.Source)) return;
                    item.IsChecked = !item.IsChecked;
                    if (item.IsChecked)
                    {
                        if (!_spellColorizer.UsedSpellCheckers.Contains(checker))
                            _spellColorizer.UsedSpellCheckers.Add(checker);
                    }
                    else
                    {
                        if (_spellColorizer.UsedSpellCheckers.Contains(checker))
                            _spellColorizer.UsedSpellCheckers.Remove(checker);
                    }
                };

                spellMenuItems.Add(item);

                if(string.IsNullOrWhiteSpace(word)) continue;
                string[] similarWords;
                var wordChecked = spellChecker.TryGetAssotiations(word, out similarWords);
                if (similarWords == null)
                {
                    item.Items.Add(wordChecked
                                       ? new MenuItem
                                           {
                                               Header = Localizing.ProvideValue("Right"),
                                               IsEnabled = false
                                           }
                                       : new MenuItem
                                           {
                                               Header = Localizing.ProvideValue("NotChecked"),
                                               IsEnabled = false
                                           });
                }
                else
                {
                    if (similarWords.Any())
                    {
                        suggestions.AddRange(similarWords.Where(w => !suggestions.Contains(w)));
                        foreach (var similarWord in similarWords)
                        {
                            var wordItem = new MenuItem { Header = similarWord };
                            item.Items.Add(wordItem);
                            wordItem.Click +=
                                (sender, args) =>
                                _document.Replace(offset, length, (string)wordItem.Header);
                        }
                    }
                    else
                    {
                        item.Items.Add(new MenuItem
                        {
                            Header = Localizing.ProvideValue("WrongButNoSuggestions"),
                            IsEnabled = false
                        });
                    }
                }
            }

            suggestions.Sort();
            foreach (var suggestion in suggestions)
            {
                var wordItem = new MenuItem { Header = suggestion };
                wordMenuItem.Items.Add(wordItem);
                wordItem.Click += (sender, args) =>_document.Replace(offset, length, (string) wordItem.Header);
            }

            return spellMenuItems;
        }
    }
}
